﻿using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace MyUtils
{
// ReSharper disable MemberCanBeInternal
	public sealed class AutoClosingMessageBox : IDisposable
// ReSharper restore MemberCanBeInternal
	{
		public void Dispose()
		{
			var ce = _closingEvent;
			if (ce != null)
			{
				ce.Close();
			}
		}

		readonly ManualResetEvent _closingEvent;
		readonly string _text;
		readonly string _caption = Guid.NewGuid().ToString();

		volatile bool _closed;

		private AutoClosingMessageBox(string text, ManualResetEvent forceCloseEvent)
		{
			_closingEvent = forceCloseEvent ?? new ManualResetEvent(false);
			_text = text;
#if DEBUG
			if (_closingEvent.WaitOne(1, false))
			{
				throw new ApplicationException("AutoClosingMessageBox forceCloseEvent passed as setted up");
			}
#endif
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
		void ShowCore()
		{
			ThreadPool.QueueUserWorkItem(delegate
			{
				_closingEvent.WaitOne();
				if (!_closed)
				{
					var pWnd = NativeMethods.FindWindow(IntPtr.Zero, _caption);
					if (pWnd != IntPtr.Zero)
					{
						// Send close command to the message box window
						NativeMethods.PostMessage(new HandleRef(null, pWnd), /*WM_CLOSE*/16, IntPtr.Zero, IntPtr.Zero);
					}
				}
			});

			try
			{
				//MessageBox(new HandleRef(null, IntPtr.Zero), _text, _caption, 0);
				MessageBox.Show(_text, _caption);
			}
			catch (ThreadAbortException)
			{
				_closingEvent.Set();
			}
			catch (ThreadInterruptedException)
			{
				_closingEvent.Set();
			}
			_closed = true;

			// free thread
			_closingEvent.Set();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="text">message to display</param>
		/// <param name="forceCloseEvent">waitHandle that should be set to close window programmatically</param>
// ReSharper disable MemberCanBeInternal
		public static void ShowDialog(string text, ManualResetEvent forceCloseEvent)
// ReSharper restore MemberCanBeInternal
		{
			using(var mbx = new AutoClosingMessageBox(text, forceCloseEvent))
			{
				mbx.ShowCore();
			}
		}

	}
}